package com.jalarbee.stock.category.business;

import java.io.Serializable;
import java.util.Collection;
import java.util.Date;
import java.util.Set;

import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToMany;
import javax.persistence.ManyToOne;
import javax.persistence.NamedQueries;
import javax.persistence.NamedQuery;
import javax.persistence.OneToMany;
import javax.persistence.Temporal;
import javax.persistence.TemporalType;

import com.jalarbee.stock.product.business.Product;
import javax.persistence.EnumType;
import javax.persistence.Enumerated;

@NamedQueries({
    @NamedQuery(name = "root.categories", query = "select c from Category c where c.parent = null"),
    @NamedQuery(name = "all.categories", query = "select c from Category c"),
    @NamedQuery(name = "leaf.categories", query = "select c from Category c where c.id not in c.parent.id"),
    @NamedQuery(name = "category.by.name", query = "select c from Category c where c.name=:name")
})
@Entity
public class Category implements Serializable {

    private static final long serialVersionUID = 1L;
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private int id;
    @Column(unique = true, nullable = false)
    private String name;
    @Column(nullable = false)
    private String description;
    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "PARENT_ID")
    private Category parent;
    @Enumerated(EnumType.STRING)
    private CategoryType categoryType;
    @OneToMany(mappedBy = "parent", fetch=FetchType.LAZY,
    cascade = {CascadeType.MERGE, CascadeType.REMOVE, CascadeType.PERSIST})
    @org.hibernate.annotations.Cascade(value = org.hibernate.annotations.CascadeType.DELETE_ORPHAN)
    private Collection<Category> children;
    @Temporal(TemporalType.TIMESTAMP)
    private Date creationDate;
    @ManyToMany(mappedBy = "categories", fetch = FetchType.LAZY)
    private Collection<Product> products;

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getDescription() {
        return description;
    }

    public void setDescription(String description) {
        this.description = description;
    }

    public Date getCreationDate() {
        return creationDate;
    }

    public void setCreationDate(Date creationDate) {
        if (creationDate == null) {
            creationDate = new Date();
        }
        this.creationDate = creationDate;
    }

    public Category getParent() {
        return parent;
    }

    public void setParent(Category parent) {
        this.parent = parent;
    }

    public Collection<Category> getChildren() {
        return children;
    }

    public void setChildren(Collection<Category> children) {
        this.children = children;
    }

    @Override
    public String toString() {
        return String.valueOf(id);
//		return name;
    }

    public void addChild(Category category) {
        category.setParent(this);
        children.add(category);
    }

    public void addChildren(Set<Category> categories) {
        for (Category category : categories) {
            category.setParent(this);
        }
        children.addAll(categories);
    }

    public void removeChild(Category category) {
        category.setParent(null);
        children.remove(category);
    }

    public void removeChildren(Set<Category> categories) {
        for (Category category : categories) {
            category.setParent(null);
        }
        children.removeAll(categories);
    }

    public Collection<Product> getProducts() {
        return products;
    }

    public void setProducts(Collection<Product> products) {
        this.products = products;
    }

    public void setCategoryType(CategoryType categoryType) {
        this.categoryType = categoryType;
    }

    public CategoryType getCategoryType() {
        return categoryType;
    }

    @Override
    public boolean equals(Object obj) {
        if(obj  == null ) 
            return false;
        if(obj == this)
            return true;
        Category category = null;
        if(obj instanceof Category) 
            category = (Category) obj;
        if(category != null) {
            return category.getId() == this.id;
        }
        return false;
    }

    @Override
    public int hashCode() {
        int i = 59;
        if(name != null) {
            return this.id * i + (name.hashCode() + i) % i + i;
        }
        return (this.id + 342) * i + i;
    }
    
}
